/*
  AdViEmulator - AdventureVision emulator
  Copyright (C) 2012-2013  JustBurn

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef CORECOP411_H
#define CORECOP411_H

#include <stdint.h>

class CoreCOP411
{
public:
	enum Exception {	// Exception
		INVALID_INSTRUCTION
	};

	CoreCOP411();
	void Reset(void);
	int ExecSingle(void);

	// Tables
	static const char *InstructionName[256];
	static const uint8_t InstructionSize[256];
	static const uint8_t InstructionCycle[256];
	void GetInstructionName(const uint8_t *dopc, uint16_t addr, char *sout);
	void GetInstructionName(uint16_t addr, char *sout);
	int GetInstructionSize(uint16_t addr);
	int GetInstructionCycles(uint16_t addr);

	// Callbacks
	virtual uint8_t OnDecodeROM(uint16_t addr) = 0;
	virtual uint8_t OnReadROM(uint16_t addr) = 0;
	virtual void OnException(Exception exception, int value) = 0;

	// Registers
	uint8_t rom[512];	// Internal RAM: 512 x 8
	uint8_t ram[32];	// Internal RAM: 32 x 4
	uint8_t accu;		// Accumulator, 4-bit
	uint8_t carry;		// Carry, 1-bit
	uint8_t ramb;		// RAM address, 6-bit
	uint8_t port_d;		// Port D, 4-bits
	uint8_t port_g;		// Port G, 4-bits
	uint8_t port_l;		// Port L, 8-bits
	uint8_t qreg;		// Q-Register for L output, 8-bits
	uint8_t skl;		// SKL, 1-bit
	uint8_t enreg;		// EN Register, 4-bits
	uint8_t sioreg;		// SIO Register, 4-bits
	uint16_t sa;		// Save A
	uint16_t sb;		// Save B
	bool skipnext;		// Skip next instruction
	bool skiplbi;		// Skip until not LBI
	union Tpc {
		struct {
			uint8_t low;
			uint8_t high;
		};
		uint16_t w;
	} pc;

private:
	int ExecSingle_Internal(void);
	int ExecSingle_33Ex(void);
	uint8_t ReadPC(void);
	uint8_t RAMRead(uint8_t addr);
	void RAMWrite(uint8_t addr, uint8_t data);
	void IORead(uint8_t ram);
	void IOWrite(uint8_t ram);
	void Push(void);
	void Pop(void);
};

#endif // CORECOP411_H
